package com.basker.pisces.collection;

import java.util.ArrayList;
import java.util.Collection;

import com.basker.pisces.IChild;

public class AbstractChildrenCollection<TParent, TItem extends IChild<TParent>> extends ArrayList<TItem> {

    private static final long serialVersionUID = 3408767601981820662L;

    protected transient TParent parent;

    protected AbstractChildrenCollection(TParent parent) {
        this.parent = parent;
    }

    @Override
    public void add(int index, TItem e) {
        setParent(e);

        super.add(index, e);
    }

    @Override
    public boolean add(TItem e) {
        setParent(e);

        return super.add(e);
    }

    @Override
    public boolean addAll(Collection<? extends TItem> c) {
        for (TItem item : c) {
            setParent(item);
        }

        return super.addAll(c);
    }

    @Override
    public boolean addAll(int index, Collection<? extends TItem> c) {
        for (TItem item : c) {
            setParent(item);
        }

        return super.addAll(index, c);
    }

    @Override
    public void clear() {
        for (TItem item : this) {
            removeParent(item);
        }

        super.clear();
    }

    public TParent getParent() {
        return this.parent;
    }

    @Override
    public TItem remove(int index) {
        TItem item = super.remove(index);
        if (item != null) {
            removeParent(item);
        }

        return item;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean remove(Object o) {
        boolean v = super.remove(o);
        if (v) {
            removeParent((TItem) o);
        }

        return v;
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean removeAll(Collection<?> c) {
        boolean v = super.removeAll(c);

        for (Object o : c) {
            removeParent((TItem) o);
        }

        return v;
    }

    protected void removeParent(TItem item) {
        item.setParent(null);
    }

    protected void setParent(TItem item) {
        item.setParent(this.getParent());
    }
}
